package pkg16b_eca.data.validate;

import java.awt.Color;
import java.awt.List;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JTextField;

public class Validate {
    /**
     * A method to validate different objects.
     * @param obj An object that the function will try to identify.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Object(final Object obj) {
        if (obj == null) return true;
        if (obj instanceof JTextField) {
            JTextField txt = (JTextField) obj;
            if (txt.getText() == null || txt.getText().isEmpty()) {
                return true;
            }
        } else if (obj instanceof JComboBox) {
            JComboBox cmb = (JComboBox) obj;
            if (cmb.getSelectedItem().toString().toLowerCase().equals("välj")) {
                return true;
            }
            ///*Testing, working*/ errorLabel.setForeground((cmb.getSelectedItem().toString().toLowerCase().equals("välj")) ? Color.red : Color.black);
            ///*Testing, working*/ return cmb.getSelectedItem().toString().toLowerCase().equals("välj") ? setColor(errorLabel, Color.red) : setColor(errorLabel, Color.black);
        } else if (obj instanceof List) {
            List lst = (List) obj;
            if (lst.getSelectedIndex() == -1) {
                return true;
            }
        } else if (obj instanceof String) {
            if (Text((String) obj)) {
                return true;
            }
        } else if (obj instanceof Integer) {
            if (Number((String) obj)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * A method to validate different objects, and coloring an error label.
     * @param obj An object that the function will try to identify.
     * @param errorLabel A label that will be colored.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Object(final Object obj, final JLabel errorLabel) {
        return setColor(errorLabel, Object(obj));
    }
    
    /**
     * A method to validate different objects.
     * @param obj An object that the function will try to identify.
     * @param errorLabel A label that will be colored.
     * @param clr The color to be set errorLabel.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Object(final Object obj, final JLabel errorLabel, final Color clr) {
        if (Object(obj)) {
            errorLabel.setForeground(clr);
            return true;
        }
        return false;
    }
    
    /**
     * A method to validate different objects.
     * @param obj An object that the function will try to identify.
     * @param errorLabel A label that will be colored.
     * @param text The text to set to the errorLabel.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Object(final Object obj, final JLabel errorLabel, final String text) {
        return setText(errorLabel, text, Object(obj));
    }
    
    /**
     * A method to validate different objects, and coloring an error label.
     * @param obj An object that the function will try to identify.
     * @param errorLabel A label that will be colored.
     * @param clr The color to be set to the errorLabel.
     * @param text The text to set to the errorLabel.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Object(final Object obj, final JLabel errorLabel, final String text, final Color clr) {
        if (Object(obj)) {
            errorLabel.setForeground(clr);
            errorLabel.setText(text);
            return true;
        }
        return false;
    }
    
    /**
     * A method to validate text.
     * @param text The text to validate.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Text(final String text) {
        return text.isEmpty();
    }

    /**
     * A method to validate text.
     * @param text The text to validate.
     * @param errorLabel A label that will be colored.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Text(final Object obj, final JLabel errorLabel) {
        if (obj instanceof JTextField && Text((String) obj)) {
            errorLabel.setForeground(Color.red);
            return true;
        } else if (!(obj instanceof JTextField)) {
            errorLabel.setForeground(Color.yellow);
        }
        else {
            errorLabel.setForeground(Color.black);
        }
        return false;
    }

    /**
     * A method to validate numbers.
     * @param number The integer value to validate.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Number(final int number) {
        return number == -1;
    }

    /**
     * A method to validate numbers, through string.
     * @param number The string value to validate.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Number(final String number) {
        return Text.parseNumber(number) == -1;
    }

    /**
     * A method to validate numbers.
     * @param obj An integer value (or something similar) to validate.
     * @param errorLabel A label that will be colored.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean Number(final Object obj, final JLabel errorLabel) {
        if (obj instanceof JTextField) {
            JTextField txt = (JTextField) obj;
            if (txt.getText() == null || txt.getText().isEmpty() || Text.parseNumber(txt.getText()) == -1) {
                errorLabel.setForeground(Color.red);
                return true;
            } else {
                errorLabel.setForeground(Color.black);
            }
        } else if (!(obj instanceof JTextField)) {
            errorLabel.setForeground(Color.yellow);
        }

        return false;
    }
    
    /**
     * Example: return cmb.getSelectedItem().toString().toLowerCase().equals("välj") ? setColor(errorLabel, Color.red) : setColor(errorLabel, Color.black);
     * @param errorLabel The error label that is getting the color.
     * @param clr Color to give the label.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean setColor(final JLabel errorLabel, final Color clr) {
        if (clr == Color.red) {
            errorLabel.setForeground(Color.red);
            return true;
        } else {
            errorLabel.setForeground(Color.black);
            return false;
        }
    }

    /**
     * Example: return cmb.getSelectedItem().toString().toLowerCase().equals("välj") ? setColor(errorLabel, Color.red) : setColor(errorLabel, Color.black);
     * @param errorLabel The error label that is getting the color.
     * @param clr Color to give the label.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean setColor(final JLabel errorLabel, final boolean error) {
        if (error) {
            errorLabel.setForeground(Color.red);
        } else {
            errorLabel.setForeground(Color.black);
        }
        return error;
    }

    /**
     * A method to set text if the boolean error is true.
     * @param text A string to set the errorLabel to if error equals to true.
     * @param errorLabel A label that will be colored.
     * @return A boolean whether the input returns an error (true) or not (false).
     */
    public static boolean setText(final JLabel errorLabel, final String text, final boolean error) {
        if (error) {
            errorLabel.setText(text);
        }
        return error;
    }
    
    /**
     * Validates a date that look like yyyy-MM-dd.
     * @param date yyyy-MM-dd
     * @return A boolean whether the input returns an error (true) or not (false). "^(\\d{4}-?\\d{2}-?\\d{2})$"
     */
    public static boolean Date(final String date) { //[6.1.1]
        String expression = "^(\\d{4}-\\d{2}-\\d{2})$"; //0000-00-00
        if (date.matches(expression)) {
            int[] dates = getDate(date);
            int monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
            int year = dates[0];
            int month = dates[1];
            int day = dates[2];
            
            if (year > 1700 && month>0 && month<13 && day>0 && day<32) {
                if (((year%4 != 0) && (year%100 == 0) || (year%400 != 0))) {
                    monthDays[1]++; //Leapyear, add one day to february.
                }
                if(day<=monthDays[month-1]) {
                    return false;
                }
            }
        }
        return true;
    }
    
    /**
     * Validates a date that look like yyyy-MM-dd.
     * @param date yyyy-MM-dd
     * @return A boolean whether the input returns an error (true) or not (false). "^(\\d{4}-?\\d{2}-?\\d{2})$"
     */
    public static boolean Date(final Object obj, final JLabel errorLabel) {
        if (obj instanceof JTextField && Date(((JTextField) obj).getText())) {
            errorLabel.setForeground(Color.red);
            return true;
        } else if (!(obj instanceof JTextField)) {
            errorLabel.setForeground(Color.yellow);
        } else {
            errorLabel.setForeground(Color.black);
        }
        return false;
    }
    
    /**
     * Validates a time that look like HH:mm:ss
     * @param time HH:mm:ss
     * @return A boolean whether the input returns an error (true) or not (false). "^(\\d{2}:?\\d{2}:?\\d{2})$"
     */
    public static boolean Time(final String time) {
        String expression = "^(\\d{2}:\\d{2}:\\d{2})$"; //00:00:00
        if (time.matches(expression)) {
            int hour = Short.parseShort(time.substring(0, 2));
            int minute = Short.parseShort(time.substring(3, 5));
            int second = Short.parseShort(time.substring(6, 8));
            
            if (hour >= 0 && hour < 24 && minute>=0 && minute<60 && second>=0 && second<60) {
                return false;
            }
        }
        return true;
        
        /*SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        try {
            java.util.Date format = sdf.parse(time);
            return new java.sql.Time(format.getTime());
        } catch (ParseException e) {
            try {
                java.util.Date format = sdf.parse(new Date().toString());
                return new java.sql.Time(format.getTime());
            } catch (ParseException e2) {
                return new Time(0);
            }
        }*/
    }
    
    /**
     * Validates a time that look like HH:mm:ss
     * @param time HH:mm:ss
     * @return A boolean whether the input returns an error (true) or not (false). "^(\\d{2}:?\\d{2}:?\\d{2})$"
     */
    public static boolean Time(final Object obj, final JLabel errorLabel) {
        if (obj instanceof JTextField && !Time(((JTextField) obj).getText())) {
            errorLabel.setForeground(Color.red);
            return true;
        } else if (!(obj instanceof JTextField)) {
            errorLabel.setForeground(Color.yellow);
        } else {
            errorLabel.setForeground(Color.black);
        }
        return false;
    }

    /** Valid email, that isn't validated: asd@asd.asd.com.
     * @param email A string that will be checked if it's an email or not.
     * @return A boolean whether the input returns an error (true) or not (false). */
    public static boolean Email(final String email) {
        String expression = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
        if (email.matches(expression)) {
            return true;
        }
        return false;
    }

    /** Valid email, that isn't validated: asd@asd.asd.com.
     * @param email A string that will be checked if it's an email or not.
     * @return A boolean whether the input returns an error (true) or not (false). */
    public static boolean Email(final Object obj, final JLabel errorLabel) {
        if (obj instanceof JTextField && !Email(((JTextField) obj).getText())) {
            errorLabel.setForeground(Color.red);
            return true;
        } else if (!(obj instanceof JTextField)) {
            errorLabel.setForeground(Color.yellow);
        } else {
            errorLabel.setForeground(Color.black);
        }
        return false;
    }
    
    /**
     * [0] = year
     * [1] = month
     * [2] = day
     * @param date The date as string
     * @return Dates as an array.
     */
    private static int[] getDate(String date) {
        String dateExpression = "^(\\d{4}-\\d{2}-\\d{2})$"; //0000-00-00
        int year = 0;
        int month = 0;
        int day = 0;
                
        if (date.matches(dateExpression)) {
            year = Short.parseShort(date.substring(0, 4));
            month = Short.parseShort(date.substring(5, 7));
            day = Short.parseShort(date.substring(8, 10));
        }
        
        return new int[] {year,month,day};
    }
    
    public static boolean DateComparing(String firstDate, String secondDate) { //[6.1.2]
        if (!Date(firstDate) && !Date(secondDate)) { //Check so that they're dates.
            //Dates cannot be exactly the same.
            if (firstDate.equalsIgnoreCase(secondDate)) {
                return true;
            }

            int[] firstDates = getDate(firstDate);
            int[] secondDates = getDate(secondDate);

            //Preventing days in slutdatum from being too low.
            if ((firstDates[0] >= secondDates[0]) && //Year
                (firstDates[1] >= secondDates[1]) && //Month
                (firstDates[2] >= secondDates[2])) { //Day
                return true; //Returns with error
                //Preventing months from being too low
            } else if ((firstDates[0] >= secondDates[0]) && //year
                       (firstDates[1] > secondDates[1])) { //Month
                return true;
                //Preventing years from being too low.
            } else if ((firstDates[0] > secondDates[0])) { //Year
                return true;
            }
        }
        return false; //Do not return error if the dates are invalid, because this is only a comarison to compare dates, validation will happen on another place. And this is also to return the correct message.
    }
    
    public static boolean DateComparing(String firstDate, String secondDate, JLabel errorLabel) {
        if (DateComparing(firstDate, secondDate)) {
            errorLabel.setText("<html>Ett datum kan inte sluta före det börjat <br>och det kan inte vara samma datum som <br>när det börjar.</html>");
            return true;
        }
        return false;
    }
}
